<script>
  import mqtt from 'mqtt'
  import { mqttConnection } from '@/utils/constant'
  // import { mergeDevicesStates } from '@/utils/device'
  import {
    generateRandStr,
    getCurrentTime,
    isJson,
    uniqueArr,
    parseTime,
  } from '@/utils'
  import { mapGetters } from 'vuex'
  export default {
    data() {
      return {
        // devices: this.$store.getters.devicesObj,
        // serialnos: this.$store.getters.devices.map(val => (val.rtu_serialno || val.serialno)),
        connection: mqttConnection,
        subscription: {
          topic: 'D/0103.0007.2038000000/#',
          qos: 0,
        },
        publish: {
          topic: 'topic/browser',
          qos: 0,
          payload: '{ "msg": "Hello, I am browser." }',
        },
        receiveNews: '',
        qosList: [
          { label: 0, value: 0 },
          { label: 1, value: 1 },
          { label: 2, value: 2 },
        ],
        client: {
          connected: false,
        },
        subscribeSuccess: false,
      }
    },
    computed: {
      ...mapGetters(['topics', 'devices', 'devicesObj']),
      serialnos() {
        const rtu_serialnos = this.devices
          .map((val) => val.rtu_serialno)
          .filter((val) => {
            return val
          })
        const serialnos = this.devices.map((val) => val.serialno)
        return uniqueArr(rtu_serialnos).concat(serialnos)
      },
      serialnosMap() {
        const res = {}
        this.devices.forEach((val) => {
          const temp = val.rtu_serialno || val.serialno
          if (!res[temp]) {
            res[temp] = [val.serialno]
          } else {
            res[temp].push(val.serialno)
          }
        })
        return res
      },
    },
    mounted() {
      this.createConnection()
    },
    methods: {
      // 创建连接
      createConnection() {
        // 连接字符串, 通过协议指定使用的连接方式
        // ws 未加密 WebSocket 连接
        // wss 加密 WebSocket 连接
        // mqtt 未加密 TCP 连接
        // mqtts 加密 TCP 连接
        // wxs 微信小程序连接
        // alis 支付宝小程序连接
        const { host, port, endpoint, ...options } = this.connection
        options.clientId = 'mqttjs_3be2c321' + generateRandStr()
        // const connectUrl = `wss://${host}:${port}${endpoint}`
        const connectUrl = `wss://${host}:${port}${endpoint}`
        // const connectUrl = `ws://10.18.1.230:8001/mqtt`
        try {
          if (!this.client.connected) {
            this.client = mqtt.connect(connectUrl, options)
          }
        } catch (error) {
          console.log('mqtt.connect error', error)
        }
        this.client.on('connect', () => {
          console.log('Connection succeeded!')
          this.client.connected = true
          this.doSubscribe()
        })
        this.client.on('error', (error) => {
          console.log('Connection failed', error)
          this.doUnSubscribe()
        })
        this.client.on('message', (topic, message) => {
          const serialno = topic.split('/').pop()
          const type = topic.split('/')[3]
          const state_raw = this.Utf8ArrayToStr(message)
          const state =
            typeof state_raw === 'string' && isJson(state_raw)
              ? JSON.parse(state_raw)
              : {}
          if (
            ['STS', 'LIVENESS'].includes(type) &&
            state &&
            this.serialnos.includes(serialno)
          ) {
            /**
             * 1.根据设备编号筛选出来设备
             * 2.将设备编号和更新后的设备状态组成对象
             * 3.更新原设备列表状态
             * 4.将更新后的设备列表推送到VUEX中
             */
            this.serialnosMap[serialno].forEach((item) => {
              const device = this.devicesObj[item]
              if (device && device.states) {
                Object.assign(device.states, state.regs)
                if (type === 'LIVENESS') {
                  Object.assign(device.states, state)
                }
                if (state.datatime) {
                  Object.assign(device.states, { datatime: state.datatime })
                }
                if (state.regs) {
                  let datatime = getCurrentTime()
                  if (state.regs.datatime) {
                    datatime = parseTime(state.regs.datatime)
                  }
                  Object.assign(device.states, { datatime })
                }
                this.$store.commit('device/SET_DEVICE', device)
              }
            })
          }
        })
      },
      doSubscribe() {
        if (!this.subscribeSuccess) {
          const { qos } = this.subscription
          this.topics.forEach((ctopic) => {
            this.client.subscribe(ctopic, qos, (error, res) => {
              if (error) {
                console.log('Subscribe to topics error', error)
                return
              }
              this.subscribeSuccess = true
              console.log('Subscribe to topics res', res)
            })
          })
        }
      },
      doUnSubscribe() {
        const { topic } = this.subscription
        this.client.unsubscribe(topic, (error) => {
          if (error) {
            console.log('Unsubscribe error', error)
          }
        })
      },
      doPublish() {
        const { topic, qos, payload } = this.publication
        this.client.publish(topic, payload, qos, (error) => {
          if (error) {
            console.log('Publish error', error)
          }
        })
      },
      destroyConnection() {
        if (this.client.connected) {
          try {
            this.client.end()
            this.client = {
              connected: false,
            }
            console.log('Successfully disconnected!')
          } catch (error) {
            console.log('Disconnect failed', error.toString())
          }
        }
      },
      Utf8ArrayToStr(array) {
        var out, i, len, c
        var char2, char3

        out = ''
        len = array.length
        i = 0
        while (i < len) {
          c = array[i++]
          switch (c >> 4) {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
              // 0xxxxxxx
              out += String.fromCharCode(c)
              break
            case 12:
            case 13:
              // 110x xxxx 10xx xxxx
              char2 = array[i++]
              out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f))
              break
            case 14:
              // 1110 xxxx 10xx xxxx 10xx xxxx
              char2 = array[i++]
              char3 = array[i++]
              out += String.fromCharCode(
                ((c & 0x0f) << 12) |
                  ((char2 & 0x3f) << 6) |
                  ((char3 & 0x3f) << 0)
              )
              break
          }
        }

        return out
      },
    },
    // eslint-disable-next-line vue/require-render-return, no-unused-vars
    render(h, context) {},
  }
</script>
